// Copyright (c) 2022 Presto Labs Pte. Ltd.
// Author: lucasyoo

#pragma once

#include <numeric>
#include <random>

#include "coin2/strategy/order_executor/layering_executor2.h"

namespace coin2::strategy::order_executor {

using IOrderSubsystem = exchange::base::order::IOrderSubsystem;
using coin2::exchange::base::symbology::IProductInfo;
using OrderContext = coin2::exchange::base::order::OrderContext;
using OrderList = std::vector<const OrderContext*>;
using LayeringExecutor = coin2::strategy::order_executor::LayeringExecutor;
using LayeringExecutor2 = coin2::strategy::order_executor::LayeringExecutor2;
using LayeringLevels = coin2::strategy::order_executor::LayeringLevels;

class LayeringExecutor3 : public LayeringExecutor2 {
 public:
  LayeringExecutor3(
      const PassiveExecutorConfig& config,
      IOrderSubsystem* os,
      std::optional<int64_t> timestamp,
      const TopBook* book,
      GetProductHolderFunc get_product_holder,
      std::optional<double> qty_tolerance_bp = std::nullopt,
      std::optional<double> lot_size_quote = std::nullopt,
      std::optional<double> avoid_qty_cancel_percent = std::nullopt,
      const bool is_randomize_post = false,
      const int cancel2order_ratio = std::numeric_limits<int>::max() - 1,
      const bool verbose = false);

  std::vector<LayeringLevels::Level> GetMostDesiredModification(
      LayeringLevels layering_levels,
      int64_t timestamp,
      int sign,
      const OrderList& wo_list,
      LayeringExecutor3* layering_executor);

  void ManageSideOrders(int64_t timestamp, int sign, LayeringLevels levels);
  void ExecuteOperation(int64_t timestamp, int sign, const LayeringLevels::Level& oper);

  OrderList GetBuyOrders() const { return wo_->GetBuyOrders(); }
  OrderList GetSellOrders() const { return wo_->GetSellOrders(); }

 private:
  std::map<std::pair<int, LayeringLevels::OperationType>, int64_t> prev_oper_ts_;
  int64_t prev_buy_cancel_ts_{0L};
  int64_t prev_sell_cancel_ts_{0L};
  std::optional<double> qty_tolerance_bp_;
  std::optional<double> avoid_qty_cancel_percent_;
  bool is_randomize_post_;
  int cancel2order_ratio_;
  int current_num_cancel_{0};
  std::random_device rd_;
  std::mt19937 gen_{rd_()};
  std::uniform_int_distribution<int> randomize_post_dist_{0, std::numeric_limits<int>::max() - 1};
};

}  // namespace coin2::strategy::order_executor
